import { ColliderContainer, ColliderContainerDef, colliderContainerFactory, ColliderType, CollisionGroup } from "../../GameDef";
import { Grid } from "../../lib/kgame/d2/Grid";
import { QuadTree } from "../../lib/kgame/d2/QuadTree";
import { BaseShape } from "../../lib/kgame/d2/shape/BaseShape";
import { ECSSceneCmp } from "../../lib/kgame/ecs/ECSSceneCmp";
import { ColliderCmp } from "../cmp/ColliderCmp";
import { WorldMgr } from "./WorldMgr";

/**
 * 碰撞管理
 */
export class ColliderMgr extends ECSSceneCmp {

    /** 碰撞器类型Map */
    colliderTypeMap = new Map<ColliderType, Set<ColliderCmp>>();
    /** 碰撞组Map */
    collisionGroupMap = new Map<CollisionGroup, Set<ColliderCmp>>();
    /** 碰撞器容器Map */
    containerMap = new Map<ColliderType, ColliderContainer>();

    private _shapeColliders: ColliderCmp[] = [];

    constructor(world: WorldMgr) {
        super();
        for (const key in ColliderType) {
            if (isNaN(key as any)) {
                const type = ColliderType[key as any];
                if (type) {
                    this.colliderTypeMap.set((ColliderType as any)[key], new Set());
                }
            }
        }
        for (const key in CollisionGroup) {
            if (isNaN(key as any)) {
                const group = CollisionGroup[key as any];
                if (group) {
                    this.collisionGroupMap.set((CollisionGroup as any)[key], new Set());
                }
            }
        }

        for (const key in colliderContainerFactory) {
            const factory = (colliderContainerFactory as any)[key] as ColliderContainerDef;
            if (factory) {
                this.containerMap.set(Number(key), factory(world.rect));
            }
        }

    }

    /**
     * 碰撞器添加
     * @param col 
     */
    onColliderAdd(col: ColliderCmp) {
        if (col.type) {
            this.colliderTypeMap.get(col.type).add(col);
            const container = this.containerMap.get(col.type);
            if (container instanceof Grid) {
                container.addItem(col, col.shape.worldAABB);
            }
        }
        if (col.group) {
            this.collisionGroupMap.get(col.group).add(col);
        }
    }

    /**
     * 碰撞器移除
     * @param col 
     */
    onColliderRemove(col: ColliderCmp) {
        if (col.type) {
            this.colliderTypeMap.get(col.type).delete(col);
            const container = this.containerMap.get(col.type);
            if (container instanceof Grid) {
                container.removeItem(col);
            }
        }
        if (col.group) {
            this.collisionGroupMap.get(col.group).delete(col);
        }
    }

    /**
     * 获取图形碰撞到的所有对应类型的碰撞器
     * @param shape 检测碰撞的图形
     * @param type 碰撞器类型
     * @returns 返回的数组是个临时变量
     */
    getShapeColliders(shape: BaseShape, type: ColliderType) {
        this._shapeColliders.length = 0;
        const cont = this.containerMap.get(type);
        cont?.getCoverItems(shape.worldAABB).forEach(col => {
            if (shape.testCollide(col.shape)) {
                this._shapeColliders.push(col);
            }
        });
        return this._shapeColliders;
    }

    /**
     *  清理所有四叉树
     */
    clearQuadTrees() {
        this.containerMap.forEach(cont => {
            if (cont instanceof QuadTree) {
                cont.clear();
            }
        })
    }

    onRemove(): void {
        this.clearQuadTrees();
        this.colliderTypeMap.clear();
        this.collisionGroupMap.clear();
        this.containerMap.clear();
        this._shapeColliders.length = 0;
    }

}